﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.IO;

namespace GMusicBox.Core
{
    #region Bass
    [SuppressUnmanagedCodeSecurity]
    public sealed class Bass
    {
        public const int BASSVERSION = 516;

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern double BASS_ChannelBytes2Seconds(int handle, long pos);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern BASSFlag BASS_ChannelFlags(int handle, BASSFlag flags, BASSFlag mask);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelGetAttribute(int handle, BASSAttribute attrib, ref float value);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_ChannelGetData(int handle, [In, Out] float[] buffer, int length);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern long BASS_ChannelGetLength(int handle, BASSMode mode);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_ChannelGetLevel(int handle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelPause(int handle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelPlay(int handle, [MarshalAs(UnmanagedType.Bool)] bool restart);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelStop(int handle);
 
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_Free();
 
        #region BASS_ChannelGetPosition
        public static long BASS_ChannelGetPosition(int handle)
        {
            return BASS_ChannelGetPosition(handle, BASSMode.BASS_POS_BYTES);
        }

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern long BASS_ChannelGetPosition(int handle, BASSMode mode);
        #endregion

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern BASSActive BASS_ChannelIsActive(int handle);
 
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelRemoveDSP(int handle, int dsp);
 
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelRemoveFX(int handle, int fx);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern long BASS_ChannelSeconds2Bytes(int handle, double pos);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelSetAttribute(int handle, BASSAttribute attrib, float value);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_ChannelSetDSP(int handle, DSPPROC proc, IntPtr user, int priority);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_ChannelSetFX(int handle, BASSFXType type, int priority);

        #region BASS_ChannelSetPosition
        public static bool BASS_ChannelSetPosition(int handle, double seconds)
        {
            return BASS_ChannelSetPosition(handle, BASS_ChannelSeconds2Bytes(handle, seconds), BASSMode.BASS_POS_BYTES);
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_ChannelSetPosition(int handle, long pos, BASSMode mode);
        #endregion

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_FXSetParameters(int handle, [In, MarshalAs(UnmanagedType.AsAny)] object par);

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern float BASS_GetCPU();
 
        #region BASS_GetDeviceInfo
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", EntryPoint = "BASS_GetDeviceInfo", CharSet = CharSet.Auto)]
        private static extern bool BASS_GetDeviceInfoInternal([In] int index, [In, Out] ref Bass_DeviceInfo info);

        public static bool BASS_GetDeviceInfo(int device, BASS_DEVICEINFO info)
        {
            bool flag = BASS_GetDeviceInfoInternal(device, ref info.a);
            if (flag)
            {
                info.name = Marshal.PtrToStringAnsi(info.a.name);
                info.driver = Marshal.PtrToStringAnsi(info.a.driver);
                info.flags = info.a.flags;
            }
            return flag;
        }

        public static BASS_DEVICEINFO BASS_GetDeviceInfo(int device)
        {
            BASS_DEVICEINFO info = new BASS_DEVICEINFO();
            if (BASS_GetDeviceInfo(device, info)) return info;
            return null;
        }

        public static BASS_DEVICEINFO[] BASS_GetDeviceInfos()
        {
            BASS_DEVICEINFO bass_deviceinfo;
            List<BASS_DEVICEINFO> list = new List<BASS_DEVICEINFO>();
            for (int i = 0; (bass_deviceinfo = BASS_GetDeviceInfo(i)) != null; i++)
            {
                list.Add(bass_deviceinfo);
            }
            BASS_GetCPU();
            return list.ToArray();
        }
        #endregion

        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_GetVersion();

        #region BASS_Init
        public static bool BASS_Init(int device, int freq, BASSInit flags, IntPtr win)
        {
            return BASS_Init(device, freq, flags, win, IntPtr.Zero);
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_Init(int device, int freq, BASSInit flags, IntPtr win, Guid clsid);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        private static extern bool BASS_Init(int device, int freq, BASSInit flags, IntPtr win, IntPtr clsid);
        #endregion

        #region BASS_StreamCreateFile
        public static int BASS_StreamCreateFile(string file, long offset, long length, BASSFlag flags)
        {
            flags |= BASSFlag.BASS_DEFAULT | BASSFlag.BASS_UNICODE;
            return BASS_StreamCreateFileUnicode(false, file, offset, length, flags);
        }

        [DllImport("bass.dll", EntryPoint = "BASS_StreamCreateFile", CharSet = CharSet.Auto)]
        private static extern int BASS_StreamCreateFileUnicode([MarshalAs(UnmanagedType.Bool)] bool memory, [In, MarshalAs(UnmanagedType.LPWStr)] string file, long offset, long length, BASSFlag flags);
        #endregion

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_StreamFree(int handle);
    }

    [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    internal struct Bass_DeviceInfo
    {
        public IntPtr name;
        public IntPtr driver;
        public BASSDeviceInfo flags;
    }

    [Serializable]
    public sealed class BASS_DEVICEINFO
    {
        internal Bass_DeviceInfo a;
        public string driver = string.Empty;
        public BASSDeviceInfo flags;
        public string name = string.Empty;

        public override string ToString()
        {
            return this.name;
        }

        public bool IsDefault
        {
            get
            {
                return ((this.flags & BASSDeviceInfo.BASS_DEVICE_DEFAULT) != BASSDeviceInfo.BASS_DEVICE_NONE);
            }
        }

        public bool IsEnabled
        {
            get
            {
                return ((this.flags & BASSDeviceInfo.BASS_DEVICE_ENABLED) != BASSDeviceInfo.BASS_DEVICE_NONE);
            }
        }

        public bool IsInitialized
        {
            get
            {
                return ((this.flags & BASSDeviceInfo.BASS_DEVICE_INIT) != BASSDeviceInfo.BASS_DEVICE_NONE);
            }
        }
    }

    [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public sealed class BASS_DX8_PARAMEQ
    {
        public float fCenter;
        public float fBandwidth;
        public float fGain;
        public BASS_DX8_PARAMEQ()
        {
            this.fCenter = 100f;
            this.fBandwidth = 18f;
        }

        public BASS_DX8_PARAMEQ(float Center, float Bandwidth, float Gain)
        {
            this.fCenter = 100f;
            this.fBandwidth = 18f;
            this.fCenter = Center;
            this.fBandwidth = Bandwidth;
            this.fGain = Gain;
        }
    }

    [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public sealed class BASS_DX8_REVERB
    {
        public float fInGain;
        public float fReverbMix;
        public float fReverbTime;
        public float fHighFreqRTRatio;
        public BASS_DX8_REVERB()
        {
            this.fReverbTime = 1000f;
            this.fHighFreqRTRatio = 0.001f;
        }

        public BASS_DX8_REVERB(float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio)
        {
            this.fReverbTime = 1000f;
            this.fHighFreqRTRatio = 0.001f;
            this.fInGain = InGain;
            this.fReverbMix = ReverbMix;
            this.fReverbTime = ReverbTime;
            this.fHighFreqRTRatio = HighFreqRTRatio;
        }
    }

    public enum BASSActive
    {
        BASS_ACTIVE_STOPPED,
        BASS_ACTIVE_PLAYING,
        BASS_ACTIVE_STALLED,
        BASS_ACTIVE_PAUSED
    }

    public enum BASSAttribute
    {
        BASS_ATTRIB_EAXMIX = 4,
        BASS_ATTRIB_FREQ = 1,
        BASS_ATTRIB_MIDI_CHANS = 0x12002,
        BASS_ATTRIB_MIDI_CPU = 0x12001,
        BASS_ATTRIB_MIDI_PPQN = 0x12000,
        BASS_ATTRIB_MIDI_TRACK_VOL = 0x12100,
        BASS_ATTRIB_MIDI_VOICES = 0x12003,
        BASS_ATTRIB_MUSIC_AMPLIFY = 0x100,
        BASS_ATTRIB_MUSIC_BPM = 0x103,
        BASS_ATTRIB_MUSIC_PANSEP = 0x101,
        BASS_ATTRIB_MUSIC_PSCALER = 0x102,
        BASS_ATTRIB_MUSIC_SPEED = 260,
        BASS_ATTRIB_MUSIC_VOL_CHAN = 0x200,
        BASS_ATTRIB_MUSIC_VOL_GLOBAL = 0x105,
        BASS_ATTRIB_MUSIC_VOL_INST = 0x300,
        BASS_ATTRIB_NOBUFFER = 5,
        BASS_ATTRIB_PAN = 3,
        BASS_ATTRIB_REVERSE_DIR = 0x11000,
        BASS_ATTRIB_TEMPO = 0x10000,
        BASS_ATTRIB_TEMPO_FREQ = 0x10002,
        BASS_ATTRIB_TEMPO_OPTION_AA_FILTER_LENGTH = 0x10011,
        BASS_ATTRIB_TEMPO_OPTION_OVERLAP_MS = 0x10015,
        BASS_ATTRIB_TEMPO_OPTION_PREVENT_CLICK = 0x10016,
        BASS_ATTRIB_TEMPO_OPTION_SEEKWINDOW_MS = 0x10014,
        BASS_ATTRIB_TEMPO_OPTION_SEQUENCE_MS = 0x10013,
        BASS_ATTRIB_TEMPO_OPTION_USE_AA_FILTER = 0x10010,
        BASS_ATTRIB_TEMPO_OPTION_USE_QUICKALGO = 0x10012,
        BASS_ATTRIB_TEMPO_PITCH = 0x10001,
        BASS_ATTRIB_VOL = 2
    }

    [Flags]
    public enum BASSData
    {
        BASS_DATA_AVAILABLE = 0,
        BASS_DATA_FFT_INDIVIDUAL = 0x10,
        BASS_DATA_FFT_NOWINDOW = 0x20,
        BASS_DATA_FFT_REMOVEDC = 0x40,
        BASS_DATA_FFT1024 = -2147483646,
        BASS_DATA_FFT16384 = -2147483642,
        BASS_DATA_FFT2048 = -2147483645,
        BASS_DATA_FFT256 = -2147483648,
        BASS_DATA_FFT4096 = -2147483644,
        BASS_DATA_FFT512 = -2147483647,
        BASS_DATA_FFT8192 = -2147483643,
        BASS_DATA_FLOAT = 0x40000000
    }

    [Flags]
    public enum BASSDeviceInfo
    {
        BASS_DEVICE_DEFAULT = 2,
        BASS_DEVICE_ENABLED = 1,
        BASS_DEVICE_INIT = 4,
        BASS_DEVICE_NONE = 0
    }

    [Flags]
    public enum BASSFlag
    {
        BASS_AAC_STEREO = 0x400000,
        BASS_AC3_DOWNMIX_2 = 0x200,
        BASS_AC3_DOWNMIX_4 = 0x400,
        BASS_AC3_DOWNMIX_DOLBY = 0x600,
        BASS_AC3_DYNAMIC_RANGE = 0x800,
        BASS_CD_C2ERRORS = 0x800,
        BASS_CD_SUBCHANNEL = 0x200,
        BASS_CD_SUBCHANNEL_NOHW = 0x400,
        BASS_DEFAULT = 0,
        BASS_FX_BPM_BKGRND = 1,
        BASS_FX_BPM_MULT2 = 2,
        BASS_FX_FREESOURCE = 0x10000,
        BASS_MIDI_DECAYEND = 0x1000,
        BASS_MIDI_DECAYSEEK = 0x4000,
        BASS_MIDI_NOFX = 0x2000,
        BASS_MIXER_BUFFER = 0x2000,
        BASS_MIXER_DOWNMIX = 0x400000,
        BASS_MIXER_END = 0x10000,
        BASS_MIXER_FILTER = 0x1000,
        BASS_MIXER_LIMIT = 0x4000,
        BASS_MIXER_MATRIX = 0x10000,
        BASS_MIXER_NONSTOP = 0x20000,
        BASS_MIXER_NORAMPIN = 0x800000,
        BASS_MIXER_PAUSE = 0x20000,
        BASS_MIXER_POSEX = 0x2000,
        BASS_MIXER_RESUME = 0x1000,
        BASS_MUSIC_3D = 8,
        BASS_MUSIC_AUTOFREE = 0x40000,
        BASS_MUSIC_DECODE = 0x200000,
        BASS_MUSIC_FLOAT = 0x100,
        BASS_MUSIC_FT2MOD = 0x2000,
        BASS_MUSIC_FX = 0x80,
        BASS_MUSIC_LOOP = 4,
        BASS_MUSIC_MONO = 2,
        BASS_MUSIC_NONINTER = 0x10000,
        BASS_MUSIC_NOSAMPLE = 0x100000,
        BASS_MUSIC_POSRESET = 0x8000,
        BASS_MUSIC_POSRESETEX = 0x400000,
        BASS_MUSIC_PRESCAN = 0x20000,
        BASS_MUSIC_PT1MOD = 0x4000,
        BASS_MUSIC_RAMP = 0x200,
        BASS_MUSIC_RAMPS = 0x400,
        BASS_MUSIC_SINCINTER = 0x800000,
        BASS_MUSIC_STOPBACK = 0x80000,
        BASS_MUSIC_SURROUND = 0x800,
        BASS_MUSIC_SURROUND2 = 0x1000,
        BASS_RECORD_PAUSE = 0x8000,
        BASS_SAMPLE_3D = 8,
        BASS_SAMPLE_8BITS = 1,
        BASS_SAMPLE_FLOAT = 0x100,
        BASS_SAMPLE_FX = 0x80,
        BASS_SAMPLE_LOOP = 4,
        BASS_SAMPLE_MONO = 2,
        BASS_SAMPLE_MUTEMAX = 0x20,
        BASS_SAMPLE_OVER_DIST = 0x30000,
        BASS_SAMPLE_OVER_POS = 0x20000,
        BASS_SAMPLE_OVER_VOL = 0x10000,
        BASS_SAMPLE_SOFTWARE = 0x10,
        BASS_SAMPLE_VAM = 0x40,
        BASS_SPEAKER_CENLFE = 0x3000000,
        BASS_SPEAKER_CENTER = 0x13000000,
        BASS_SPEAKER_FRONT = 0x1000000,
        BASS_SPEAKER_FRONTLEFT = 0x11000000,
        BASS_SPEAKER_FRONTRIGHT = 0x21000000,
        BASS_SPEAKER_LEFT = 0x10000000,
        BASS_SPEAKER_LFE = 0x23000000,
        BASS_SPEAKER_PAIR1 = 0x1000000,
        BASS_SPEAKER_PAIR10 = 0xa000000,
        BASS_SPEAKER_PAIR11 = 0xb000000,
        BASS_SPEAKER_PAIR12 = 0xc000000,
        BASS_SPEAKER_PAIR13 = 0xd000000,
        BASS_SPEAKER_PAIR14 = 0xe000000,
        BASS_SPEAKER_PAIR15 = 0xf000000,
        BASS_SPEAKER_PAIR2 = 0x2000000,
        BASS_SPEAKER_PAIR3 = 0x3000000,
        BASS_SPEAKER_PAIR4 = 0x4000000,
        BASS_SPEAKER_PAIR5 = 0x5000000,
        BASS_SPEAKER_PAIR6 = 0x6000000,
        BASS_SPEAKER_PAIR7 = 0x7000000,
        BASS_SPEAKER_PAIR8 = 0x8000000,
        BASS_SPEAKER_PAIR9 = 0x9000000,
        BASS_SPEAKER_REAR = 0x2000000,
        BASS_SPEAKER_REAR2 = 0x4000000,
        BASS_SPEAKER_REAR2LEFT = 0x14000000,
        BASS_SPEAKER_REAR2RIGHT = 0x24000000,
        BASS_SPEAKER_REARLEFT = 0x12000000,
        BASS_SPEAKER_REARRIGHT = 0x22000000,
        BASS_SPEAKER_RIGHT = 0x20000000,
        BASS_STREAM_AUTOFREE = 0x40000,
        BASS_STREAM_BLOCK = 0x100000,
        BASS_STREAM_DECODE = 0x200000,
        BASS_STREAM_PRESCAN = 0x20000,
        BASS_STREAM_RESTRATE = 0x80000,
        BASS_STREAM_STATUS = 0x800000,
        BASS_UNICODE = -2147483648,
        BASS_WV_STEREO = 0x400000
    }

    public enum BASSFXType
    {
        BASS_FX_BFX_APF = 0x1000e,
        BASS_FX_BFX_AUTOWAH = 0x10009,
        BASS_FX_BFX_BQF = 0x10013,
        BASS_FX_BFX_CHORUS = 0x1000d,
        BASS_FX_BFX_COMPRESSOR = 0x1000f,
        BASS_FX_BFX_COMPRESSOR2 = 0x10011,
        BASS_FX_BFX_DAMP = 0x10008,
        BASS_FX_BFX_DISTORTION = 0x10010,
        BASS_FX_BFX_ECHO = 0x10001,
        BASS_FX_BFX_ECHO2 = 0x1000a,
        BASS_FX_BFX_ECHO3 = 0x1000c,
        BASS_FX_BFX_FLANGER = 0x10002,
        BASS_FX_BFX_LPF = 0x10006,
        BASS_FX_BFX_MIX = 0x10007,
        BASS_FX_BFX_PEAKEQ = 0x10004,
        BASS_FX_BFX_PHASER = 0x1000b,
        BASS_FX_BFX_REVERB = 0x10005,
        BASS_FX_BFX_ROTATE = 0x10000,
        BASS_FX_BFX_VOLUME = 0x10003,
        BASS_FX_BFX_VOLUME_ENV = 0x10012,
        BASS_FX_DX8_CHORUS = 0,
        BASS_FX_DX8_COMPRESSOR = 1,
        BASS_FX_DX8_DISTORTION = 2,
        BASS_FX_DX8_ECHO = 3,
        BASS_FX_DX8_FLANGER = 4,
        BASS_FX_DX8_GARGLE = 5,
        BASS_FX_DX8_I3DL2REVERB = 6,
        BASS_FX_DX8_PARAMEQ = 7,
        BASS_FX_DX8_REVERB = 8
    }

    [Flags]
    public enum BASSInit
    {
        BASS_DEVICE_3D = 4,
        BASS_DEVICE_8BITS = 1,
        BASS_DEVICE_CPSPEAKERS = 0x400,
        BASS_DEVICE_DEFAULT = 0,
        BASS_DEVICE_LATENCY = 0x100,
        BASS_DEVICE_MONO = 2,
        BASS_DEVICE_NOSPEAKER = 0x1000,
        BASS_DEVICE_SPEAKERS = 0x800,
        BASS_DEVIDE_DMIX = 0x2000
    }

    [Flags]
    public enum BASSMode
    {
        BASS_MIDI_DECAYSEEK = 0x4000,
        BASS_MIXER_NORAMPIN = 0x800000,
        BASS_MUSIC_POSRESET = 0x8000,
        BASS_MUSIC_POSRESETEX = 0x400000,
        BASS_POS_BYTES = 0,
        BASS_POS_DECODE = 0x10000000,
        BASS_POS_DECODETO = 0x20000000,
        BASS_POS_MIDI_TICK = 2,
        BASS_POS_MUSIC_ORDERS = 1
    }

    public delegate void DSPPROC(int handle, int channel, IntPtr buffer, int length, IntPtr user);
    #endregion
    #region BassMix
    [SuppressUnmanagedCodeSecurity]
    public sealed class BassMix
    {
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bassmix.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_Mixer_ChannelRemove(int handle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bassmix.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_Mixer_StreamAddChannel(int handle, int channel, BASSFlag flags);
 
        [DllImport("bassmix.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_Mixer_StreamCreate(int freq, int chans, BASSFlag flags);
    }
    #endregion
    #region BassWaDsp
    [SuppressUnmanagedCodeSecurity]
    public class BassWaDsp
    {
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_ChannelRemoveDSP(int plugin);

        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_WADSP_ChannelSetDSP(int plugin, int handle, int priority);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_Config(int plugin);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_Free();

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_FreeDSP(int plugin);

        #region BASS_WADSP_GetName
        public static string BASS_WADSP_GetName(int plugin)
        {
            IntPtr ptr = BASS_WADSP_GetNamePtr(plugin);
            if (ptr != IntPtr.Zero)
            {
                return Marshal.PtrToStringAnsi(ptr);
            }
            return null;
        }

        [DllImport("bass_wadsp.dll", EntryPoint = "BASS_WADSP_GetName", CharSet = CharSet.Auto)]
        private static extern IntPtr BASS_WADSP_GetNamePtr(int plugin);
        #endregion

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_Init(IntPtr win);

        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_WADSP_Load([In, MarshalAs(UnmanagedType.LPWStr)] string dspfile, int x, int y, int width, int height, WINAMPWINPROC proc);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_PluginInfoFree();

        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern int BASS_WADSP_PluginInfoGetModuleCount();

        #region BASS_WADSP_PluginInfoGetName
        public static string BASS_WADSP_PluginInfoGetName()
        {
            IntPtr ptr = BASS_WADSP_PluginInfoGetNamePtr();
            if (ptr != IntPtr.Zero)
            {
                return Marshal.PtrToStringAnsi(ptr);
            }
            return null;
        }

        [DllImport("bass_wadsp.dll", EntryPoint = "BASS_WADSP_PluginInfoGetName", CharSet = CharSet.Auto)]
        private static extern IntPtr BASS_WADSP_PluginInfoGetNamePtr();
        #endregion

        #region BASS_WADSP_PluginInfoGetModuleName
        public static string BASS_WADSP_PluginInfoGetModuleName(int module)
        {
            IntPtr ptr = BASS_WADSP_PluginInfoGetModuleNamePtr(module);
            if (ptr != IntPtr.Zero)
            {
                return Marshal.PtrToStringAnsi(ptr);
            }
            return null;
        }

        [DllImport("bass_wadsp.dll", EntryPoint = "BASS_WADSP_PluginInfoGetModuleName", CharSet = CharSet.Auto)]
        private static extern IntPtr BASS_WADSP_PluginInfoGetModuleNamePtr(int module);
        #endregion

        public static string[] BASS_WADSP_PluginInfoGetModuleNames()
        {
            List<string> list = new List<string>();
            int module = 0;
            string item = string.Empty;
            while (item != null)
            {
                item = BASS_WADSP_PluginInfoGetModuleName(module);
                module++;
                if (item != null)
                    list.Add(item);
            }
            Bass.BASS_GetCPU();
            return list.ToArray();
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_PluginInfoLoad([In, MarshalAs(UnmanagedType.LPWStr)] string dspfile);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_SetFileName(int plugin, [In, MarshalAs(UnmanagedType.LPStr)] string file);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_SetSongTitle(int plugin, [In, MarshalAs(UnmanagedType.LPStr)] string title);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_Start(int plugin, int module, int handle);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("bass_wadsp.dll", CharSet = CharSet.Auto)]
        public static extern bool BASS_WADSP_Stop(int plugin);
    }

    public delegate int WINAMPWINPROC(IntPtr hwnd, int msg, int wParam, int lParam);

    public sealed class WINAMP_DSP
    {
        private WINAMP_DSP()
        {
            File = string.Empty;
            Description = string.Empty;
            StartedModule = -1;
        }

        static WINAMP_DSP()
        {
            PlugIns = new List<WINAMP_DSP>();
        }

        internal WINAMP_DSP(string fileName)
        {
            File = fileName;
            Description = string.Empty;
            StartedModule = -1;
            if (BassWaDsp.BASS_WADSP_PluginInfoLoad(File))
            {
                Description = BassWaDsp.BASS_WADSP_PluginInfoGetName();
                ModuleCount = BassWaDsp.BASS_WADSP_PluginInfoGetModuleCount();
                ModuleNames = BassWaDsp.BASS_WADSP_PluginInfoGetModuleNames();
                BassWaDsp.BASS_WADSP_PluginInfoFree();
            }
        }

        private static bool HasPlugin(string fileName)
        {
            foreach (WINAMP_DSP winamp_dsp in PlugIns)
                if (winamp_dsp.File.ToLower().Equals(fileName.ToLower()))
                    return true;

            return false;
        }

        public static void FindPlugins(string path)
        {
            foreach (string str in Directory.GetFiles(path, "dsp_*.dll"))
            {
                if (!HasPlugin(str))
                {
                    WINAMP_DSP item = new WINAMP_DSP(str);
                    if (item.ModuleCount > 0)
                        PlugIns.Add(item);
                }
            }
        }

        public bool Load()
        {
            if (IsLoaded)
                BassWaDsp.BASS_WADSP_FreeDSP(Handle);
            Handle = BassWaDsp.BASS_WADSP_Load(File, 5, 5, 100, 100, null);
            return (Handle != 0);
        }

        public bool SetFilename(string filename)
        {
            return ((IsLoaded && IsStarted) && BassWaDsp.BASS_WADSP_SetFileName(Handle, filename));
        }

        public bool SetSongTitle(string title)
        {
            return ((IsLoaded && IsStarted) && BassWaDsp.BASS_WADSP_SetSongTitle(Handle, title));
        }

        public bool ShowEditor()
        {
            return ((IsLoaded && (StartedModule >= 0)) && BassWaDsp.BASS_WADSP_Config(Handle));
        }

        public int Start(int module, int channel, int prio)
        {
            if ((!IsLoaded || (module < 0)) || ((module >= ModuleCount) || (channel == 0)))
            {
                return 0;
            }
            if (IsStarted)
            {
                this.Stop();
            }
            StartedModule = 0;
            StartedModule = -1;
            BassWaDsp.BASS_WADSP_Start(Handle, module, channel);
            StartedModule = module;
            StartedModule = BassWaDsp.BASS_WADSP_ChannelSetDSP(Handle, channel, prio);
            return StartedModule;
        }

        public bool Stop()
        {
            if (IsLoaded)
            {
                if (IsStarted && !BassWaDsp.BASS_WADSP_ChannelRemoveDSP(Handle))
                {
                    return false;
                }
                if (BassWaDsp.BASS_WADSP_Stop(Handle))
                {
                    StartedModule = 0;
                    StartedModule = -1;
                    return true;
                }
            }
            return false;
        }

        public override string ToString()
        {
            return string.Format("{0} ({1})", Description, Path.GetFileNameWithoutExtension(File));
        }

        public bool Unload()
        {
            if (IsStarted)
            {
                this.Stop();
            }
            if (IsLoaded)
            {
                BassWaDsp.BASS_WADSP_FreeDSP(Handle);
                Handle = 0;
                return true;
            }
            return false;
        }

        public int ChannelHandle { get; private set; }
        public string Description { get; private set; }
        public string File { get; private set; }
        public int Handle { get; private set; }
        public bool IsLoaded { get { return Handle != 0; } }
        public bool IsStarted { get { return ChannelHandle != 0; } }
        public int ModuleCount { get; private set; }
        public string[] ModuleNames{ get; private set; }
        public static List<WINAMP_DSP> PlugIns{ get; private set; }
        public int StartedModule { get; private set; }
    }

    #endregion
}
